package com.ibeeking.found.org.b.rest.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ibeeking.found.org.b.rest.service.IEmployeeFieldService;
import com.ibeeking.found.org.service.common.dos.EmployeeFieldDO;
import com.ibeeking.found.org.service.common.dos.EmployeeFieldOptionsDO;
import com.ibeeking.found.org.service.common.enums.EmployeeFieldDataTypeEnum;
import com.ibeeking.found.org.service.common.param.EmployeeFieldOptionsItemParam;
import com.ibeeking.found.org.service.common.param.EmployeeFieldParam;
import com.ibeeking.found.org.service.common.param.EmployeeFieldSwitchParam;
import com.ibeeking.found.org.service.common.query.EmployeeFieldPageQuery;
import com.ibeeking.found.org.service.common.vo.EmployeeFieldOptionsItemParamVO;
import com.ibeeking.found.org.service.common.vo.EmployeeFieldVO;
import com.ibeeking.found.org.service.mapper.EmployeeFieldMapper;
import com.ibeeking.found.org.service.mapper.EmployeeFieldOptionsMapper;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName EmployeeFieldServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2022-01-24 11:39
 **/
@Service
public class EmployeeFieldServiceImpl extends ServiceImpl<EmployeeFieldMapper, EmployeeFieldDO> implements IEmployeeFieldService {

    @Resource
    private EmployeeFieldMapper employeeFieldMapper;

    @Resource
    private EmployeeFieldOptionsMapper employeeFieldOptionsMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(EmployeeFieldParam param) {
        Integer fieldType = param.getFieldType();
        if (fieldType == 0) {
            // 固有字段为上线时手动添加到数据库 只做浏览展示 不做修改操作
            throw BusinessException.create("添加自定义字段失败 不能添加固有字段!");
        }
        // 查询已经添加过的自定义字段
        LambdaQueryWrapper<EmployeeFieldDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EmployeeFieldDO::getFieldType, 1);
        Integer count = employeeFieldMapper.selectCount(queryWrapper);
        if (count >= 10) {
            throw BusinessException.create("添加自定义字段失败 最多可以添加10个扩展自定义字段!");
        }
        queryWrapper.eq(EmployeeFieldDO::getCode, param.getCode());
        queryWrapper.or().eq(EmployeeFieldDO::getName, param.getName());
        EmployeeFieldDO entityDO = employeeFieldMapper.selectOne(queryWrapper);

        if (ObjectUtil.isNotNull(entityDO)) {
            throw BusinessException.create("添加自定义字段失败 自定义字段已经存在 请检查编码或名称");
        }
        EmployeeFieldDO entityFieldDO = BeanUtil.convertBean(param, EmployeeFieldDO.class);
        entityFieldDO.setCreateTime(LocalDateTime.now());
        entityFieldDO.setModifyTime(LocalDateTime.now());
        int insert = employeeFieldMapper.insert(entityFieldDO);
        if (insert > 0) {
            param.setId(entityFieldDO.getId());
            // 如果是单选框或者多选框 则需要处理数据选项
            modifyFieldOptions(param);
            return true;
        } else {
            throw BusinessException.create("添加自定义字段失败!");
        }
    }

    @Override
    public Page<EmployeeFieldVO> pageList(EmployeeFieldPageQuery pageQuery) {
        Page<EmployeeFieldDO> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());

        LambdaQueryWrapper<EmployeeFieldDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(pageQuery.getName()), EmployeeFieldDO::getName, pageQuery.getName());
        queryWrapper.like(StringUtils.isNotBlank(pageQuery.getCode()), EmployeeFieldDO::getCode, pageQuery.getCode());
        queryWrapper.eq(ObjectUtil.isNotNull(pageQuery.getHasModify()), EmployeeFieldDO::getHasModify, pageQuery.getHasModify());
        queryWrapper.eq(ObjectUtil.isNotNull(pageQuery.getHasShow()), EmployeeFieldDO::getHasShow, pageQuery.getHasShow());
        queryWrapper.orderByAsc(EmployeeFieldDO::getFieldType);
        queryWrapper.orderByDesc(EmployeeFieldDO::getCreateTime);
        Page<EmployeeFieldDO> pages = employeeFieldMapper.selectPage(page, queryWrapper);
        Page<EmployeeFieldVO> EmployeeFieldVoPageResult = BeanUtil.convertPage(pages, EmployeeFieldVO.class);
        wrapperVo(EmployeeFieldVoPageResult.getRecords());
        return EmployeeFieldVoPageResult;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean modify(EmployeeFieldParam param) {
        EmployeeFieldDO infoFieldDo = employeeFieldMapper.selectById(param.getId());
        if (ObjectUtil.isNull(infoFieldDo)) {
            throw BusinessException.create("更新失败 自定义字段配置信息不存在!");
        }
        Integer fieldType = infoFieldDo.getFieldType();
        if (fieldType == 0 && param.getFieldType() == 1) {
            throw BusinessException.create("更新失败 固有字段配置信息不能更新为自定义字段!");
        }
        if (infoFieldDo.getFieldType() == 0 && !infoFieldDo.getCode().equals(param.getCode())) {
            // 固有字段 code不可以变更
            throw BusinessException.create("更新失败 固有字段配置信息Code不能变更!");
        }
        EmployeeFieldDO entityFieldDO = BeanUtil.convertBean(param, EmployeeFieldDO.class);
        entityFieldDO.setModifyTime(LocalDateTime.now());
        // 单选框或多选框需保存选项
        modifyFieldOptions(param);
        return employeeFieldMapper.updateById(entityFieldDO) > 0;
    }

    @Override
    public EmployeeFieldVO view(Long id) {
        EmployeeFieldDO entityFieldDO = employeeFieldMapper.selectById(id);
        if (ObjectUtil.isNull(entityFieldDO)) {
            throw BusinessException.create("查询失败 字段配置信息不存在!");
        }
        EmployeeFieldVO entityFieldVO = BeanUtil.convertBean(entityFieldDO, EmployeeFieldVO.class);
        wrapperVo(Collections.singletonList(entityFieldVO));
        wrapperVoFieldOptions(entityFieldVO);
        return entityFieldVO;
    }

    @Override
    public Boolean modifySwitch(EmployeeFieldSwitchParam param) {
        EmployeeFieldDO entityFieldDO = BeanUtil.convertBean(param, EmployeeFieldDO.class);
        entityFieldDO.setModifyTime(LocalDateTime.now());
        return employeeFieldMapper.updateById(entityFieldDO) > 0;
    }


    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public Boolean del(Long id) {
        EmployeeFieldDO infoFieldDo = employeeFieldMapper.selectById(id);
        if (ObjectUtil.isNull(infoFieldDo)) {
            throw BusinessException.create("删除失败 自定义字段配置信息不存在!");
        }
        if (infoFieldDo.getFieldType() == 0) {
            throw BusinessException.create("删除失败 固有字段配置信息不可以删除!");
        }
        boolean delStatus = employeeFieldMapper.deleteById(id) > 0;
        if (delStatus) {
            LambdaUpdateWrapper<EmployeeFieldOptionsDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(EmployeeFieldOptionsDO::getFieldId, id);
            employeeFieldOptionsMapper.delete(updateWrapper);
        }
        return delStatus;
    }

    @Override
    public void modifyFieldOptions(EmployeeFieldParam param) {
        Integer dataType = param.getDataType();
        List<Integer> boxCodeList = Arrays.asList(EmployeeFieldDataTypeEnum.CHECK_BOX_MANY.getCode(), EmployeeFieldDataTypeEnum.CHECK_BOX_ONE.getCode());
        if (!boxCodeList.contains(dataType)) {
            return;
        }
        List<EmployeeFieldOptionsItemParam> dataItems = param.getOptionsItemList();
        if (Collections3.isEmpty(dataItems)) {
            throw BusinessException.create("操作失败 多选框或单选框必须定义选项");
        }

        Long EmployeeFieldId = param.getId();
        // 需要先将之前的数据删除
        LambdaUpdateWrapper<EmployeeFieldOptionsDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(EmployeeFieldOptionsDO::getFieldId, EmployeeFieldId);
        employeeFieldOptionsMapper.delete(updateWrapper);
        // 添加数据
        List<EmployeeFieldOptionsDO> optionsDoList = new ArrayList<>();
        for (EmployeeFieldOptionsItemParam item : dataItems) {
            EmployeeFieldOptionsDO addItem = new EmployeeFieldOptionsDO();
            addItem.setCreateTime(LocalDateTime.now());
            addItem.setModifyTime(LocalDateTime.now());
            addItem.setFieldId(EmployeeFieldId);
            addItem.setOptionsMsg(item.getOptionsMsg());
            addItem.setOptionsValue(item.getOptionsValue());
            addItem.setChecked(item.getChecked());
            addItem.setCreateTime(LocalDateTime.now());
            addItem.setModifyTime(LocalDateTime.now());
            optionsDoList.add(addItem);
        }
        employeeFieldOptionsMapper.insertBatchSomeColumn(optionsDoList);
    }

    private void wrapperVo(List<EmployeeFieldVO> list) {
        if (Collections3.isEmpty(list)) {
            return;
        }
        list.forEach(
                x -> {
                    x.setDataTypeName(EmployeeFieldDataTypeEnum.getName(x.getDataType()));
                    x.setFieldTypeName(x.getFieldType() == 0 ? "固有字段" : "自定义字段");
                }
        );
    }


    private void wrapperVoFieldOptions(EmployeeFieldVO vo) {
        if (ObjectUtil.isNull(vo)) {
            return;
        }

        LambdaQueryWrapper<EmployeeFieldOptionsDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EmployeeFieldOptionsDO::getFieldId, vo.getId());
        List<EmployeeFieldOptionsDO> fieldOptionsDoList = employeeFieldOptionsMapper.selectList(queryWrapper);

        if (Collections3.isNotEmpty(fieldOptionsDoList)) {
            vo.setOptionsItemList(fieldOptionsDoList.stream().map(x -> new EmployeeFieldOptionsItemParamVO()
                    .setOptionsValue(x.getOptionsValue())
                    .setOptionsMsg(x.getOptionsMsg())
                    .setChecked(x.getChecked())
            ).collect(Collectors.toList()));
        }
    }
}
